//----------------------------------*-C++-*----------------------------------//
/*!
 * \file   Cell_Field.hh
 * \author Jeremy Roberts
 * \date   Jul 6, 2011
 * \brief  Field data for cells.
 * \note   Copyright (C) 2011 Jeremy Roberts. 
 */
//---------------------------------------------------------------------------//
// $Rev::                                               $:Rev of last commit
// $Author::                                            $:Author of last commit
// $Date::                                              $:Date of last commit
//---------------------------------------------------------------------------//

#ifndef CELL_FIELD_HH_
#define CELL_FIELD_HH_

#include "tran/Field.hh"
#include "tran/CartMesh.hh"

namespace slabtran
{

//===========================================================================//
/*!
 * \class Cell_Field
 * \brief A container of values associated with cells of a mesh.
 *
 * Since the Cell_Field is inherently associated with a mesh, we force
 * construction with the mesh.  Moreover, at a given cell, there may be more
 * than one unknown.  This is the case e.g. for flux moments or for advanced
 * spatial discretizations.  In either case, the constructor also supports a
 * second parameter for the number of unknowns per cell, defaulted to one.
 *
 * Const and mutable access is available through the operator () via cardinal
 * cell index.  Const access is available through the value() interface via
 * ijk indices.
 *
 * \todo Cell_Field has the mesh as a protected member.  Since all fields
 *       are supposed to be data on a mesh, we could move the mesh member
 *       to the base class (i.e. Field).
 *
 * \tparam T The type of each field element (may be accessed via value_type).
 *
 */
/*!
 * \example test/testCell_Field
 *
 * Test of Cell_Field.
 */
//===========================================================================//
template <class T>
class Cell_Field : public Field<T>
{
public:

  //! \name Typedefs for use with Cell_Field
  //\{
  typedef Field<T> Base;
  typedef typename Base::value_type value_type;
  typedef typename Base::reference reference;
  typedef typename Base::const_reference const_reference;
  typedef typename Base::pointer pointer;
  typedef typename Base::const_pointer const_pointer;
  typedef typename Base::iterator iterator;
  typedef typename Base::const_iterator const_iterator;
  typedef typename Base::size_type size_type;
  typedef typename Base::difference_type difference_type;
  // convenience type
  typedef Base_Mesh::SP_mesh SP_mesh;
  //\}

  /*!
   * \brief Constructor.
   *
   * \param mesh              Mesh we live on.
   * \param number_per_cell   Number of unknowns per cell.
   * \param init_val          Initial value for all members of field.
   *
   * \note
   * We initialize to "0" by using the funtion T().  This only works
   * for intrinsic numerical types e.g. double, int.  However, these
   * are basically all we plan to store on a mesh.  It might be possible
   * to create a class static function to do the same.
   *
   */
  inline explicit Cell_Field(SP_mesh mesh, int number_per_cell = 1,
                             T init_val = T());

  /*!
   *  \brief Constant reference to a cell unknown value (3-d).
   *
   *  \param    i           X index
   *  \param    j           Y index
   *  \param    k           Z index
   *  \param    unknown     Node index
   *  \return               Cell field value at cell node.
   */
  const value_type&
  value(const int i, const int j, const int k, const int unknown) const
  {
    Require(unknown < d_number_per_cell);
    int index = d_mesh->convert(i, j, k) * d_number_per_cell + unknown;
    Ensure(this->valid_index(index));
    return this->d_values[index];
  }

  /*!
   *  \brief Constant reference to a cell unknown value (2-d).
   *
   *  \param    i           X index
   *  \param    j           Y index
   *  \param    unknown     Node index
   *  \return               Cell field value at cell node.
   */
  const value_type&
  value(const int i, const int j, const int unknown) const
  {
    Require(unknown < d_number_per_cell);
    int index = d_mesh->convert(i, j, 0) * d_number_per_cell + unknown;
    Ensure(this->valid_index(index));
    return this->d_values[index];
  }

  /*!
   *  \brief Constant reference to a cell unknown value (1-d).
   *
   *  \param    i           X index
   *  \param    unknown     Node index
   *  \return               Const reference to cell field value at cell node.
   */
  const value_type&
  value(const int i, const int unknown) const
  {
    Require(unknown < d_number_per_cell);
    int index = d_mesh->convert(i, 0, 0) * d_number_per_cell + unknown;
    Ensure(this->valid_index(index));
    return this->d_values[index];
  }

  /*!
   * \brief Mutable reference to a cell value by cardinal index.
   *
   * \param     cell        Cell cardinal index.
   * \param     unknown     Node index.
   * \return                Mutable reference to cell field value at cell node.
   */
  value_type& operator()
  (const int cell, const int unknown = 0)
  {
    Require(unknown < d_number_per_cell);
    Require(cell < d_mesh->number_cells());
    int index = cell + unknown;
    Ensure(this->valid_index(index));
    return this->d_values[index];
  }

  /*!
   * \brief Const reference to a cell value by cardinal index.
   *
   * \param     cell        Cell cardinal index.
   * \param     unknown     Node index.
   * \return                Const reference to cell field value at cell node.
   */
  const value_type& operator()
  (const int cell, const int unknown = 0) const
  {
    Require(unknown < d_number_per_cell);
    Require(cell < d_mesh->number_cells());
    int index = cell + unknown;
    Ensure(this->valid_index(index));
    return this->d_values[index];
  }

protected:

  // >>> DATA

  /// mesh we live on; not needed now
  SP_mesh d_mesh;

  /// number of unknowns per cell
  const int d_number_per_cell;

};

//---------------------------------------------------------------------------//
// INLINE FUNCTIONS
//---------------------------------------------------------------------------//

template <class T>
Cell_Field<T>::Cell_Field(SP_mesh mesh, int number_per_cell, T init_val)
 :   Field<T> (mesh->number_cells() * number_per_cell, init_val)
   , d_mesh(mesh)
   , d_number_per_cell(number_per_cell)
{
  Require(d_mesh);                // Require a constructed mesh.
  Require(d_number_per_cell > 0); // Require at least one unknown per cell.
}

} // end namespace slabtran


#endif /* CELL_FIELD_HH_ */

//---------------------------------------------------------------------------//
//              end of Cell_Field.hh
//---------------------------------------------------------------------------//
